package com.pphh.demo;

import com.pphh.demo.exception.BlockException;

import java.time.Instant;
import java.util.concurrent.*;

/**
 * Please add description here.
 *
 * @author huangyinhuang
 * @date 11/14/2018
 */
public class FlowControlTestFramework {

    private static final int TEST_THREAD_COUNT = 10;
    private static final int DEFAULT_TEST_DURATION = 10;
    private ExecutorService executorService;

    public FlowControlTestFramework() {
        this.executorService = new ThreadPoolExecutor(
                TEST_THREAD_COUNT * 2, TEST_THREAD_COUNT * 2,
                DEFAULT_TEST_DURATION, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
    }

    public void execute(final FlowControl flowControl) {
        Monitor.getInstance().tick();

        for (int i = 0; i < TEST_THREAD_COUNT; i++) {

            // start the testing thread
            final Future future = this.executorService.submit(new Runnable() {
                @Override
                public void run() {
                    Instant end = Instant.now().plusSeconds(DEFAULT_TEST_DURATION);
                    while (Instant.now().isBefore(end)) {
                        Monitor.getInstance().incrementTotal();
                        try {
                            flowControl.run();
                            Monitor.getInstance().incrementPass();
                        } catch (BlockException e) {
                            Monitor.getInstance().incrementBlock();
                        } catch (Exception e) {
                            System.out.println("Received an unexpected exception, exit testing...");
                            break;
                        }
                    }
                }
            });

        }

        shutdownAndAwaitTermination(this.executorService);
    }

    void shutdownAndAwaitTermination(ExecutorService pool) {
        // Disable new tasks from being submitted
        pool.shutdown();
        try {
            // Wait a while for existing tasks to terminate
            if (!pool.awaitTermination(DEFAULT_TEST_DURATION + 5, TimeUnit.SECONDS)) {
                // Cancel currently executing tasks
                pool.shutdownNow();

                // Wait a while for tasks to respond to being cancelled
                if (!pool.awaitTermination(DEFAULT_TEST_DURATION, TimeUnit.SECONDS)) {
                    System.err.println("Pool did not terminate");
                }
            }
        } catch (InterruptedException ie) {
            // (Re-)Cancel if current thread also interrupted
            pool.shutdownNow();
            // Preserve interrupt status
            Thread.currentThread().interrupt();
        }

        Monitor.getInstance().stop();
    }

}
